"""
This is the main benchmark script for the check and resolve procedure.
Created: May 7th
First version May 7th. Things begin to work as expected.

Todo:
Output result on instance from 10 to 100 with or without heuristics

Author: Derek Zhang
"""

import cplex
import random
import numpy as np
import sys
from time import time 
from ccfs.fscplex import fscplex
from ccfs.callbacks import CheckBigM

# Setup range
ni_lo = int(sys.argv[1])
ni_up = int(sys.argv[2])
ni_de = int(sys.argv[3])

ns_lo = int(sys.argv[1])
ns_up = int(sys.argv[2])
ns_de = int(sys.argv[3])

# Print header of the table
f = open("../output/bench_checkbigmresolve.txt", 'w')
header =  "%4s %4s" % ('NI', 'NS')
header += "%10s %10s " % ("SIP Obj",  "SIP(M) Obj")
header += "%10s %10s " % ("SIP Nodes", "SIP(M) Nodes")
header += "%10s %10s"  %  ('SIP Time', 'SIP(M) Time')
header += "%10s"       % ("Iter")
header += "\n"
f.write(header)

# Main loop over the NI and NS
for NI in range(ni_lo, ni_up, ni_de):
    for NS in range(ns_lo, ns_up, ns_de):
        fc = fscplex()
        fc.generate_instance(NI, NS, eps=0.2, Ordered=False)
        fc.parameters.read_file("../../param/stofac.prm")
        #fc.get_x_heur()
        #fc.strengthen_formulation()

        t0 = time()
        fc.solve()
        t1 = time()

        sip_x_val = fc.solution.get_values(fc.x_name)
        sip_y_val = fc.solution.get_values(fc.y_name)
        sip_obj_val = fc.solution.get_objective_value()
        sip_nodes = fc.solution.progress.get_num_nodes_processed()
        sip_time = t1 - t0

        delta = 1.0
        #Start with bigm_val to be 0
        bigm_val = [0] * fc.num_bigm

        for s in fc.S:
            #if y_val[s] == 1.0:
            if 1:
                for i in fc.I:
                    ind = i + s*fc.NI
                    #bigm_val[ind] = 0.1
                    # Naive set initial values of bigm
                    #print s, i
                    if 1:
                    #if fc.rhs[s][i] - fc.xi[i] > 0:
                        #fc.rhs[s][i] - fc.xi[i] >= 0:
                        #bigm_val[ind] = max(fc.rhs[s][i] - sip_x_val[i]-3*random.uniform(0,1), 0)
                        bigm_val[ind] = 0.1
                        #bigm_val[ind] = 0.2 * (fc.rhs[s][i] - fc.xi[i])
                    else:
                        bigm_val[ind] = 0

                    #Use heuristic solution ( Expected to be better than naive initial values ) 
                    #bigm_val[ind] = max(0, fc.rhs[s][i] - fc.x_heur[i])

                    # Cheating use the true solution ( Should take one iter since optimality condition is satisfied)
                    #bigm_val[ind] = max(0, fc.rhs[s][i] - x_val[i] + 0.3) #2 * abs(random.normalvariate(1,1)))

                
        fc.set_bigm(bigm_val)        
        fc.register_callback(CheckBigM)

        iter = 0

        # Start check and resolve procedure
        t0 = time()
        while(iter < NI*NS*2):
            iter += 1
            fc.flag[0] = 1
            fc.solve()
            if fc.flag[0] == 1: #pass all the test
                #print "finish loop"
                #print fc.solution.progress.get_num_nodes_processed()
                break
            elif fc.flag[0] == 0: #binding being checked
                #print fc.solution.progress.get_num_nodes_processed()
                #fc.increase_bigm(step_length=delta)
                fc.increase_bigm(step_length=delta)
                #fc.increase_bigm(step_ratio=0.1)
        fc.unregister_callback(CheckBigM)
        fc.solve()
        t1 = time()

        sipm_time = t1-t0
        sipm_obj_val = fc.solution.get_objective_value() 
        sipm_nodes = fc.solution.progress.get_num_nodes_processed()
        # Write the results for each case 
        line = "%4d %4d  " % (NI, NS)
        line += "%10f %10f" % (sip_obj_val, sipm_obj_val)
        line += "%10d %10d" % (sip_nodes, sipm_nodes)
        line += "%10f %10f"% (sip_time, sipm_time)
        line += "%10d" % (iter)
        line += "\n"
        f.write(line)
        fc = []


f.close()
